package com.liao.library.lifecycle.livedata;

import ohos.aafwk.ability.ILifecycle;
import ohos.aafwk.ability.ILifecycleObserver;
import ohos.aafwk.ability.Lifecycle;
import ohos.aafwk.ability.LifecycleStateObserver;
import ohos.aafwk.content.Intent;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class LiveData<T> implements ILifecycleObserver {
    private int mActiveCount = 0;
    private boolean mDispatchingValue;
    private boolean mDispatchInvalidated;
    private volatile Object mData;
    static final Object NOT_SET = new Object();
    volatile Object mPendingData = NOT_SET;
    private int mVersion;
    static final int START_VERSION = -1;
    Map<Observer<? super T>, LifecycleBoundObserver> mObservers = new ConcurrentHashMap<Observer<? super T>, LifecycleBoundObserver>();

    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }

    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }

    public void observe(ILifecycle owner, Observer<? super T> observer) {
        if (owner.getLifecycle().getLifecycleState() == Lifecycle.Event.ON_STOP) {
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        if (mObservers.containsKey(observer)) {
            LifecycleBoundObserver existing = mObservers.get(observer);
            if (!existing.isAttachedTo(owner)) {
                throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
            }
        } else {
            mObservers.put(observer, wrapper);
            owner.getLifecycle().addObserver(wrapper);
        }

    }

    public T getValue() {
        return (T) mData;
    }

    protected void setValue(T value) {
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

    public void removeObserver(final Observer<? super T> observer) {
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
    }

    void dispatchingValue(ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (ObserverWrapper wrapper : mObservers.values()) {
                    considerNotify(wrapper);
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

    /**
     * 激活函数
     */
    protected void onActive() {
    }

    /**
     * 取消激活函数
     */
    protected void onInactive() {
    }

    abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        protected ObserverWrapper(Observer<? super T> mObserver) {
            this.mObserver = mObserver;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(ILifecycle owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }

            mActive = newActive;
            boolean wasInactive = mActiveCount == 0;
            mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleStateObserver {
        ILifecycle mOwner;

        public LifecycleBoundObserver(ILifecycle owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getLifecycleState().compareTo(Lifecycle.Event.ON_INACTIVE) >= 0;
        }

        @Override
        boolean isAttachedTo(ILifecycle owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }

        @Override
        public void onStateChanged(Lifecycle.Event event, Intent intent) {
            if (mOwner.getLifecycle().getLifecycleState() == Lifecycle.Event.ON_STOP) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
    }
}
